package com.dingreading.cloud.gateway.filters;

import com.alibaba.fastjson.JSONObject;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.dingreading.cloud.common.util.JsonUtil;
import com.dingreading.cloud.common.util.RedisParam;
import com.dingreading.cloud.gateway.dto.XcxVerifyDto;
import com.dingreading.cloud.gateway.entity.Members;
import com.dingreading.cloud.gateway.entity.XcxStudentLogin;
import com.dingreading.cloud.gateway.service.MembersService;
import com.dingreading.cloud.gateway.service.XcxStudentLoginService;
import com.dingreading.cloud.gateway.util.MonoUtil;
import com.dingreading.cloud.gateway.util.MstErrorCode;
import com.dingreading.cloud.gateway.util.redis.RedisService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpCookie;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import reactor.core.publisher.Mono;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.net.URI;
import java.util.Collections;
import java.util.List;

/***
 * 精读小程序端用户鉴权（手机号登录）
 */
@Component
public class JdXcxAuthGatewayFilterFactory extends AbstractGatewayFilterFactory<JdXcxAuthGatewayFilterFactory.Config> {


    private static final String REDIS_XCX_MOBILE_KEY = "jdxcx_mobile_login_";

    private static final String TOKEN_HEADER_NAME = "JD_XCX_TOKEN";

    private static final String LOGIN_TYPE_XCX_MOBILE = "JD_XCX_MOBILE";
    @Resource
    private MembersService membersService;
    @Resource
    private XcxStudentLoginService xcxStudentLoginService;
    @Resource
    private RedisService redisService;

    public static JdXcxAuthGatewayFilterFactory util;

    @PostConstruct
    public void init() {
        util = this;
    }

    public JdXcxAuthGatewayFilterFactory() {
        super(Config.class);
    }

    @Override
    public List<String> shortcutFieldOrder() {

        return Collections.singletonList("value");
    }

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            ServerHttpResponse response = exchange.getResponse();
            ServerHttpRequest request = exchange.getRequest();

            // 登录验证
            Mono<Void> authResult = auth(request, response);
            if (authResult != null) {
                return authResult;
            }

            return chain.filter(exchange);
        };
    }

    /**
     * 登录验证
     */
    private Mono<Void> auth(ServerHttpRequest request, ServerHttpResponse response) {
        URI uri = request.getURI();
        if (uri != null) {
            String path = uri.getPath();
            // 跳过验证：小程序手机号登录、发送验证码、swagger等公共接口
            if (path.contains("/api-docs") || path.contains("/getPicCode") || path.contains("/login"))
                return null;
        }

        try {

        } catch (JWTVerificationException e) {
            e.printStackTrace();
            return MonoUtil.writeResponse(response, MstErrorCode.TOKEN_INVALID.getCode(), "令牌已失效，请重新登录");
        } catch (Exception e) {
            e.printStackTrace();
            return MonoUtil.writeResponse(response, MstErrorCode.SYSTEM_ERROR.getCode(), "鉴权时发生未知错误");
        }

        return null;
    }

    /**
     * 验证小程序用户信息（基于手机号）
     *
     * @param studentUid   uid
     * @return 验证结果 DTO
     */
    public static XcxVerifyDto verifyXcxUserByMobile(String studentUid, String agencyUid) {
        // 1. 优先从Redis缓存获取
        String json = (String) util.redisService.get(REDIS_XCX_MOBILE_KEY + studentUid + "-" + agencyUid);
        if (StringUtils.isNotBlank(json)) {
            return JSONObject.parseObject(json, XcxVerifyDto.class);
        }

        Members members = util.membersService.getByStudentUid(studentUid, agencyUid);
        if (members == null) {
            return new XcxVerifyDto(MstErrorCode.TOKEN_INVALID.getCode(), "用户不存在");
        }
        if (!members.getEnabled().equals(1)) {
            return new XcxVerifyDto(MstErrorCode.TOKEN_INVALID.getCode(), "账号已被禁用");
        }

        XcxStudentLogin loginLog = util.xcxStudentLoginService.getLastLoginLogByMobile(studentUid, agencyUid, LOGIN_TYPE_XCX_MOBILE);
        if (loginLog == null) {
            return new XcxVerifyDto(MstErrorCode.TOKEN_INVALID.getCode(), "未查询到登录信息，请重新登录");
        }
        if (loginLog.getExpireTime().getTime() < System.currentTimeMillis()) {
            return new XcxVerifyDto(MstErrorCode.TOKEN_INVALID.getCode(), "登录已过期，请重新登录");
        }


        // 3. 构建DTO并存入缓存
        XcxVerifyDto staffDto = new XcxVerifyDto(MstErrorCode.SUCCESS.getCode(), "ok", loginLog.getLoginTime());
        util.redisService.set(
                REDIS_XCX_MOBILE_KEY + studentUid + "-" + agencyUid,
                JsonUtil.toJsonString(staffDto), RedisParam.HOUR_TIME
        );
        // 缓存1小时
        return staffDto;
    }

    /**
     * 从请求头中获取Token
     */
    public static String getToken(MultiValueMap<String, HttpCookie> cookies) {
        HttpCookie cookie = cookies.getFirst(TOKEN_HEADER_NAME);
        if (cookie == null)
            return "";

        return cookie.getValue();
    }

    // 内部配置类，可以保持不变
    public static class Config {
        private String value;

        public String getValue() {
            return value;
        }

        public void setValue(String value) {
            this.value = value;
        }
    }
}

